// AC 改编自 山东潍坊老师B站 kunkka

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 2;
vector<int> G[N];

struct UnionFind {
  int fa[N], siz[N];
  void init(int n) {
    for (int i = 1; i <= n; ++i)
      fa[i] = i, siz[i] = 1;
  }
  int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
  void merge(int x, int y) {
    x = find(x), y = find(y);
    if (x == y)
      return;
    if (siz[x] > siz[y])
      swap(x, y);
    fa[x] = y, siz[y] += siz[x];
    /*  按秩合并是指在合并两个集合时，总是将较小的树(秩较小的树)合并到较大的树(秩较大的树)下
    "秩"可以理解为树的高度或节点数量的近似值
    这种策略可以保持树的平衡，避免形成长链状结构
  */
  }

  int size(int p) { return siz[find(p)]; }
} tree;

set<int> s;

int main() {

  int n, m;
  cin >> n >> m;
  for (int i = 1; i <= m; ++i) {
    int u, v;
    cin >> u >> v;
    G[u].push_back(v), G[v].push_back(u); // 无向图
  }
  tree.init(n);

  for (int k = 1; k <= n; k++) {
    for (auto son : G[k]) {
      if (son < k) {
        tree.merge(k, son);
      } else {
        s.insert(son);
      }
    }
    s.erase(k);
    // 方法如果传入一个不存在的key，不会抛出异常也不会报错，它会安全地返回0（表示没有元素被删除）。
    // 这是std::set的标准行为。
    if (tree.size(1) == k) {
      cout << s.size() << endl;
    } else {
      cout << -1 << endl;
    }
  }

  return 0;
}